﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.Intrinsics.X86;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Acme.BookStore.RBACIServices;
using Acme.BookStore.RBACTable;
using HIS;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;


namespace Acme.BookStore.RBACServices
{
    [ApiExplorerSettings(GroupName = "v1")]
    public class UserServices: ApplicationService, UserIServices
    {
        /// <summary>
        /// 用户仓储
        /// </summary>
        private readonly IRepository<UserInfo> UserInfoRepository;
        /// <summary>
        /// 角色仓储
        /// </summary>
        private readonly IRepository<Role> RoleRepository;
        /// <summary>
        /// 权限仓储
        /// </summary>
        private readonly IRepository<Permissions> PermissionsRepository;
        /// <summary>
        /// 用户角色中间表仓储
        /// </summary>
        private readonly IRepository<UserRole> UserRoleRepository;
        /// <summary>
        /// 角色权限中间表仓储
        /// </summary>
        private readonly IRepository<RolePer> RolePerRepository;
        private readonly Microsoft.AspNetCore.Hosting.IHostingEnvironment environment;
        private readonly TimeSpan _interval = TimeSpan.FromMinutes(5);
        private readonly IHttpContextAccessor _httpContextAccessor;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="userInfoRepository">用户仓储</param>
        /// <param name="roleRepository">角色仓储</param>
        /// <param name="permissionsRepository">权限仓储</param>
        /// <param name="userRoleRepository">用户角色中间表仓储</param>
        /// <param name="rolePerRepository">角色权限中间表仓储</param>
        public UserServices(IRepository<UserInfo> userInfoRepository, IRepository<Role> roleRepository, IRepository<Permissions> permissionsRepository, IRepository<UserRole> userRoleRepository, IRepository<RolePer> rolePerRepository, Microsoft.AspNetCore.Hosting.IHostingEnvironment environment, IHttpContextAccessor httpContextAccessor
            )
        {
            UserInfoRepository = userInfoRepository;
            RoleRepository = roleRepository;
            PermissionsRepository = permissionsRepository;
            UserRoleRepository = userRoleRepository;
            RolePerRepository = rolePerRepository;
            this.environment = environment;
            _httpContextAccessor = httpContextAccessor;
        }


        /// <summary>
        /// 生成数字验证码
        /// </summary>
        /// <returns>返回验证码的动图路由和验证码的值</returns>
        [HttpGet("api/GenerateNumericCaptcha")]
        public async Task<APIResult<CaptchaDTO>> GenerateNumericCaptcha()
        {
            APIResult<CaptchaDTO> result = new APIResult<CaptchaDTO>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();

                // 生成6位随机数字验证码
                string captchaValue = GenerateRandomNumericCode(6);

                // 生成验证码动图
                string imagePath = GenerateCaptchaImage(captchaValue);

                 CaptchaDTO captchaDTO= new CaptchaDTO();
                var Request = _httpContextAccessor.HttpContext?.Request;
                captchaDTO.CaptchaUrl = $"{Request.Scheme}://{Request.Host}{imagePath}";
                captchaDTO.CaptchaChar=captchaValue;
                result.Data = captchaDTO;
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
            }
            return await Task.FromResult(result);
        }
        /// <summary>
        /// 生成验证码
        /// </summary>
        /// <param name="length">验证码长度</param>
        /// <returns></returns>
        private string GenerateRandomNumericCode(int length)
        {
            List<string> source = new List<string>();

            for (int i = 0; i < 10; i++) { 
                source.Add(i.ToString());
            }

            for (int i = 'a'; i <= 'z'; i++)
            {
                source.Add(((char)i).ToString());
            }

            for (int i = 'A'; i <= 'Z'; i++)
            {
                source.Add(((char)i).ToString());
            }

            Random random = new Random();

            List<string> charList = new List<string>();
            for (int i = 0; i < length; i++) {
                var c = source[random.Next(0,source.Count - 1)];
                charList.Add(c);
            }

            return string.Concat(charList);
        }
        /// <summary>
        /// 生产验证码图片
        /// </summary>
        /// <param name="captchaValue">验证码图片</param>
        /// <returns></returns>
        private string GenerateCaptchaImage(string captchaValue)
        {
            int width = 220;
            int height = 80;
            // 创建指定宽高的空白位图对象作为画布
            var bitmap = new Bitmap(width, height);

            // 创建Graphics对象用于在位图上进行绘图操作
            var graphics = Graphics.FromImage(bitmap);

            // 创建验证码文字的字体样式（Arial字体、40号、加粗）
            var font = new Font("Arial", 40, FontStyle.Bold);

            // 创建黑色笔刷用于绘制文字
            var brush = new SolidBrush(Color.Black);

            // 创建白色笔刷用于填充背景
            var backgroundBrush = new SolidBrush(Color.White);

            // 用白色笔刷填充整个画布背景（从左上角0,0到width,height）
            graphics.FillRectangle(backgroundBrush, 0, 0, width, height);

            // 在坐标(1,1)位置绘制验证码文字（使用指定字体和黑色笔刷）
            graphics.DrawString(captchaValue, font, brush, 1, 1);

            //string imagePath = Path.Combine("wwwroot", "captcha", $"{Guid.NewGuid()}.png");
            //Directory.CreateDirectory(Path.GetDirectoryName(imagePath));

            // 确保 captcha 文件夹存在
            var captchaFolder = Path.Combine(environment.WebRootPath, "captcha");
            if (!Directory.Exists(captchaFolder))
            {
                Directory.CreateDirectory(captchaFolder);
            }

            // 生成唯一文件名
            var fileName = $"{Guid.NewGuid().ToString("n")}_{DateTime.Now.Ticks}.png";
            // 虚拟路径
            var virtualPath = $"/captcha/{fileName}";

            // 物理路径
            var imagePath = Path.Combine(captchaFolder, fileName);


            bitmap.Save(imagePath, ImageFormat.Png);

            return virtualPath;
        }
        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="UserName">用户名称</param>
        /// <param name="UserPassword">用户密码</param>
        /// <returns>返回任务</returns>
        [HttpGet("api/Login")]
        public async Task<APIResult<LoginUserDTO>> Login(string UserNickname, string UserPassword)
        {
            APIResult<LoginUserDTO> result = new APIResult<LoginUserDTO>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                if (string.IsNullOrEmpty(UserNickname) || string.IsNullOrEmpty(UserPassword))
                {
                    throw new Exception("用户名或密码不能为空");
                }

                var list = from a in await UserInfoRepository.GetListAsync()
                           join b in await UserRoleRepository.GetListAsync() on a.Id equals b.UserId
                           join c in await RoleRepository.GetListAsync() on b.RoleId equals c.Id
                           join d in await RolePerRepository.GetListAsync() on c.Id equals d.RoleId
                           join e in await PermissionsRepository.GetListAsync() on d.PerId equals e.Id
                           where a.UserNickname == UserNickname
                           select new LoginUserDTO
                           {
                               UserId = a.Id,
                               UserName = a.UserName,
                               UserNickname = a.UserNickname,
                               UserPhone = a.UserPhone,
                               UserPassword = a.UserPassword,
                               ErrorCount = a.ErrorCount,
                               IsLocked = a.IsLocked,
                               RoleId = c.Id,
                               RoleName = c.RoleName,
                               PerId = e.Id,
                               PerName = e.PerName,
                               PerChar = e.PerChar
                           };
                //用户不存在
                if (list.Count() == 0)
                {
                    throw new Exception("用户不存在");
                }
                var user = list.FirstOrDefault();
                //用户已锁定
                if (user.IsLocked == true)
                {
                    throw new Exception("用户已锁定");
                }
                UserInfo user1 = new UserInfo();
                user1 = await UserInfoRepository.GetAsync(x => x.Id == user.UserId);
                //密码错误
                if (user.UserPassword != UserPassword)
                {
                    
                    //错误次数+1
                    user.ErrorCount++;
                    user1.ErrorCount++;
                    //错误次数大于等于3次，锁定用户
                    if (user.ErrorCount >= 3)
                    {
                        user.IsLocked = true;
                        user1.IsLocked = true;
                    }
                    await UserInfoRepository.UpdateAsync(user1);

                    if (user.IsLocked == true)
                    {
                        throw new Exception("用户已锁定,请联系管理员");
                    }

                    throw new Exception($"密码错误,剩余{3-user.ErrorCount}次");
                }
                //登录成功后生成Token
                user.Token=CreateTokenString(user1);
                //登录成功清零
                user1.ErrorCount = 0;
                user1.IsLocked = false;
                await UserInfoRepository.UpdateAsync(user1);
                result.Data = user;
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message =e.Message;
                //throw;
            }
            return await Task.FromResult(result);

        }
        /// <summary>
        /// 生成 JWT Token（令牌）
        /// </summary>
        /// <returns></returns>
        private string CreateTokenString(UserInfo user)
        {
            IList<Claim> claims = new List<Claim> {
                         new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
                         new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName),

                     };

            //私钥
            var secretByte = Encoding.UTF8.GetBytes("kdsfldsflkdslkflkdsflkdslfdslkflk");
            // 非对称加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            // 使用256 生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            // 生成Token
            var token = new JwtSecurityToken(
                issuer: "BeiJingBW",
                audience: "BeiJingBW",
                 claims: claims,
                  notBefore: DateTime.UtcNow,
                expires: DateTime.Now.AddDays(1), // 一天后过期
                signingCredentials: signingCredentials
            );
            // 生成token 字符串
            var strToken = new JwtSecurityTokenHandler().WriteToken(token);
            return strToken;
        }
        /// <summary>
        /// 添加用户信息
        /// </summary>
        /// <param name="userInfo">用户信息</param>
        /// <returns>返回任务</returns>
        [HttpPost("api/AddUser")]
        public async Task<APIResult<object>> AddUser(UserInfoDTO userInfoDTO)
        {
            APIResult<object> result = new APIResult<object>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                //查询用户名是否已存在
                var list =await UserInfoRepository.GetListAsync(x => x.UserNickname == userInfoDTO.UserNickname || x.UserName == userInfoDTO.UserName);
                if (list.Count()!=0)
                {
                    throw new Exception("用户已存在");
                }
                //使用DTO映射
                UserInfo userInfo= ObjectMapper.Map<UserInfoDTO, UserInfo>(userInfoDTO);
                result.Data=await UserInfoRepository.InsertAsync(userInfo);
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
                //throw;
            }
            return await Task.FromResult(result);
        }
        /// <summary>
        /// 修改用户信息
        /// </summary>
        /// <param name="userInfo">用户信息</param>
        /// <returns>返回任务</returns>
        [HttpPut("api/UpdateUser")]
        public async Task<APIResult<object>> UpdateUser(UserInfoDTO userInfoDTO)
        {
            APIResult<object> result = new APIResult<object>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                
                var userInfo = await UserInfoRepository.FirstOrDefaultAsync(x => x.Id == userInfoDTO.Id);
                //查询用户名是否已存在
                var list = await UserInfoRepository.GetListAsync(x =>x.Id!=userInfoDTO.Id  &&  (x.UserNickname == userInfoDTO.UserNickname || x.UserName == userInfoDTO.UserName));
                if (list.Count() != 0)
                {
                    throw new Exception("用户已存在");
                }
                //使用DTO映射
                ObjectMapper.Map(userInfoDTO, userInfo);
                result.Data = await UserInfoRepository.UpdateAsync(userInfo);
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
                //throw;
            }
            return await Task.FromResult(result);
        }
        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="UserNickname">用户昵称</param>
        /// <param name="UserName">用户名</param>
        /// <returns>返回任务</returns>
        [HttpGet("api/GetUser")]
        public async Task<APIResult<List<UserInfoDTO>>> GetUser(string? UserNickname, string? UserName)
        {
            APIResult<List<UserInfoDTO>> result = new APIResult<List<UserInfoDTO>>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                //获取用户信息
                var data = await UserInfoRepository.GetListAsync();
                //查询用户昵称
                if (!string.IsNullOrEmpty(UserNickname))
                {
                    data=data.Where(x=>x.UserNickname.Contains(UserNickname)).ToList();
                }
                //查询用户名
                if (!string.IsNullOrEmpty(UserName))
                {
                    data = data.Where(x => x.UserName.Contains(UserName)).ToList();
                }
                
                result.Data = ObjectMapper.Map<List<UserInfo>, List<UserInfoDTO>>(data.ToList());
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
                //throw;
            }
            return await Task.FromResult(result);

        }
        /// <summary>
        /// 添加角色
        /// </summary>
        /// <param name="roleDTO">角色信息</param>
        /// <returns>返回任务</returns>
        [HttpPost("api/AddRole")]
        public async Task<APIResult<object>> AddRole(RoleDTO roleDTO)
        {
            APIResult<object> result = new APIResult<object>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                //查询角色名是否已存在
                var list = await RoleRepository.GetListAsync(x=>x.RoleName==roleDTO.RoleName);
                if (list.Count() != 0)
                {
                    throw new Exception("角色已存在");
                }
                //使用DTO映射
                Role role = ObjectMapper.Map<RoleDTO, Role>(roleDTO);
                result.Data = await RoleRepository.InsertAsync(role);
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
                //throw;
            }
            return await Task.FromResult(result);
        }
        /// <summary>
        /// 添加权限
        /// </summary>
        /// <param name="perDTO">权限信息</param>
        /// <returns>返回任务</returns>
        [HttpPost("api/AddPer")]
        public async Task<APIResult<object>> AddPer(PermissionsDTO perDTO)
        {
            APIResult<object> result = new APIResult<object>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                //查询角色名是否已存在
                var list = await PermissionsRepository.GetListAsync(x => x.PerName==perDTO.PerName);
                if (list.Count() != 0)
                {
                    throw new Exception("权限已存在");
                }
                //使用DTO映射
                Permissions permissions = ObjectMapper.Map<PermissionsDTO, Permissions>(perDTO);
                result.Data = await PermissionsRepository.InsertAsync(permissions);
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
                //throw;
            }
            return await Task.FromResult(result);
        }
        /// <summary>
        /// 用户分配角色
        /// </summary>
        /// <param name="UserId">用户Id</param>
        /// <param name="RoleId">角色Id</param>
        /// <returns>返回任务</returns>
        [HttpPost("api/UserAllocationRole")]
        public async Task<APIResult<object>> UserAllocationRole(int UserId,int RoleId)
        {
            APIResult<object> result = new APIResult<object>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                //查询角色名是否已存在
                var list = await UserRoleRepository.GetListAsync(x => x.UserId==UserId && x.RoleId==RoleId);
                if (list.Count() != 0)
                {
                    throw new Exception("该角色用户已拥有");
                }
                UserRole userRole = new UserRole()
                {
                    UserId = UserId,
                    RoleId = RoleId,
                };
                result.Data = await UserRoleRepository.InsertAsync(userRole);
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
                //throw;
            }
            return await Task.FromResult(result);
        }
        /// <summary>
        /// 角色分配权限
        /// </summary>
        /// <param name="RoleId">角色Id</param>
        /// <param name="PerId">权限Id</param>
        /// <returns>返回任务</returns>
        [HttpPost("api/RoleAllocationPer")]
        public async Task<APIResult<object>> RoleAllocationPer(int RoleId, int PerId)
        {
            APIResult<object> result = new APIResult<object>();
            try
            {
                result.Code = CodeEnum.success;
                result.Message = CodeEnum.success.ToString();
                //查询角色名是否已存在
                var list = await RolePerRepository.GetListAsync(x => x.RoleId == RoleId && x.PerId == PerId);
                if (list.Count() != 0)
                {
                    throw new Exception("该角色用户已拥有");
                }
                RolePer rolePer = new RolePer()
                {
                    RoleId = RoleId,
                    PerId = PerId
                };
                result.Data = await RolePerRepository.InsertAsync(rolePer);
            }
            catch (Exception e)
            {
                result.Code = CodeEnum.error;
                result.Message = CodeEnum.error.ToString() + e.Message;
                //throw;
            }
            return await Task.FromResult(result);
        }
    }
}
